package com.igo.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.igo.domain.datacollection.devicedata.DeviceDataCalcd;
import com.igo.domain.datacollection.devicedata.DeviceInfo;
import com.igo.domain.datacollection.devicedata.FlatCarData;
import com.igo.domain.datacollection.devicedata.GantryCraneCaData;
import com.igo.enums.devicedata.CalcdTypeEnum;
import com.igo.enums.devicedata.GantryCraneTypeEnum;
import com.igo.enums.devicedata.LoadTypeEnum;
import com.igo.enums.devicedata.LoadValidEnum;
import com.igo.mapper.devicedata.GantryCraneCaDataMapper;
import com.igo.service.devicedata.DeviceDataCalcdService;
import com.igo.service.devicedata.GantryCraneCaDataService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.awt.geom.Point2D;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Component
public class DeivceDataCalculateGantryCraneCa {

    private ExecutorService es = Executors.newFixedThreadPool(2000);
    @Resource
    private GantryCraneCaDataMapper gantryCraneCaDataMapper;

    @Resource
    private GantryCraneCaDataService gantryCraneCaDataService;

    @Resource
    private DeviceDataCalcdService deviceDataCalcdService;

//    private Date startTime;
//
//    private Date endTime;


//    public void calculateTime(String strStartTime, String strEndTime) {
//        startTime = DateUtil.parse(strStartTime);
//        endTime = DateUtil.parse(strEndTime);
//        Calendar calendar = Calendar.getInstance();
//        calendar.setTime(startTime);
//        calendar.add(Calendar.HOUR, 00);//时
//        calendar.add(Calendar.MINUTE, 00);//分
//        calendar.add(Calendar.SECOND, 00);//秒
//        startTime = calendar.getTime();
//        calendar.setTime(endTime);
//        calendar.add(Calendar.HOUR, 23);//时
//        calendar.add(Calendar.MINUTE, 59);//分
//        calendar.add(Calendar.SECOND, 59);//秒
//        endTime = calendar.getTime();
//    }
//    public void calculateData(){
//        String strStartTime = "2024-12-01 00:00:00";
//        Date start = DateUtil.parse(strStartTime);
//        String strEndTime = "2024-12-27 23:59:59";
//        Date end = DateUtil.parse(strEndTime);
//        while(start.compareTo(end)<=0){
//            endTime = DateUtil.offset(start, DateField.DAY_OF_MONTH, 1);
//            endTime=DateUtil.offset(endTime, DateField.SECOND, -1);
//            calculateGantryCraneCaData(start,endTime);
//            start=DateUtil.offset(endTime, DateField.SECOND, 1);
//        }
//
//    }
    //计算数据
    //门吊任务明细
//    @Transactional(rollbackFor = Exception.class)


    public void calculateGantryCraneCaData(Date strStartTime, Date strEndTime) {

        //时间
        List<DeviceDataCalcd> deviceDataCalcds = new ArrayList<>();
        Comparator<GantryCraneCaData> comparator = Comparator.comparing(GantryCraneCaData::getDataTime,Comparator.naturalOrder());
        //查询向前未纳入计算的数据
        List<GantryCraneCaData> updateGantryCraneCaDatas = new ArrayList<>();
        List<GantryCraneCaData> origingantryCraneCaData = gantryCraneCaDataMapper
                .selectJoinList(GantryCraneCaData.class,new MPJLambdaWrapper<GantryCraneCaData>()
                        .selectAll(GantryCraneCaData.class)
                        .eq(GantryCraneCaData::getRunningState,"1")
                        .ge(GantryCraneCaData::getCreateTime,strStartTime).le(GantryCraneCaData::getCreateTime, strEndTime)
                        .innerJoin(DeviceInfo.class, DeviceInfo::getDeviceNo, GantryCraneCaData::getDeviceNo)
                        .selectAs(DeviceInfo::getProductId,GantryCraneCaData::getProductId)
                        .selectAs(DeviceInfo::getLoadCapacity,GantryCraneCaData::getMaxLoadCapacity)
                        .eq(DeviceInfo::getProductId,"3")
                        .eq(GantryCraneCaData::getIsCalculate,"0")
                        .orderByAsc(GantryCraneCaData::getDataTime));
        List<GantryCraneCaData> gantryCraneCaDatas = new ArrayList<>();
        for (int i = 0; i < origingantryCraneCaData.size(); i+=5) {
            gantryCraneCaDatas.add(origingantryCraneCaData.get(i));
        }
//        按载重计算数据
        //设备编号
        Set<String> deviceNos = gantryCraneCaDatas.stream().map(GantryCraneCaData::getDeviceNo).collect(Collectors.toSet());
        //计算总载重
        gantryCraneCaDatas.stream().forEach(gantryCraneCaData -> {
            BigDecimal sumLoadCapacity= new BigDecimal("0");
            if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(gantryCraneCaData.getLoadCapacityValue1())){
                try {
                    BigDecimal loadCapacityValue1 = new BigDecimal(gantryCraneCaData.getLoadCapacityValue1());
                    sumLoadCapacity=sumLoadCapacity.add(loadCapacityValue1);
                }catch (NumberFormatException e){
                    //过滤错误数据
                }
            }
            if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(gantryCraneCaData.getLoadCapacityValue2())){
                try {
                    BigDecimal loadCapacityValue2 = new BigDecimal(gantryCraneCaData.getLoadCapacityValue2());
                    sumLoadCapacity=sumLoadCapacity.add(loadCapacityValue2);
                }catch (NumberFormatException e){
                    //过滤错误数据
                }
            }
            if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(gantryCraneCaData.getLoadCapacityValue3())){
                try {
                    BigDecimal loadCapacityValue3 = new BigDecimal(gantryCraneCaData.getLoadCapacityValue3());
                    sumLoadCapacity=sumLoadCapacity.add(loadCapacityValue3);
                }catch (NumberFormatException e){
                    //过滤错误数据
                }
            }
            if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(gantryCraneCaData.getLoadCapacityValue4())){
                try {
                    BigDecimal loadCapacityValue4 = new BigDecimal(gantryCraneCaData.getLoadCapacityValue4());
                    sumLoadCapacity=sumLoadCapacity.add(loadCapacityValue4);
                }catch (NumberFormatException e){
                    //过滤错误数据
                }
            }
            gantryCraneCaData.setLoadCapacity(sumLoadCapacity);

        });
        List<List<GantryCraneCaData>> gantryCraneCaTaskList=new ArrayList<>();
        deviceNos.stream().forEach(deviceNo->{
            List<GantryCraneCaData> originalGantryCraneCaList = gantryCraneCaDatas.stream().sorted(comparator)
                    .filter(gantryCraneCaData ->
                            gantryCraneCaData.getDeviceNo().equals(deviceNo))
                    .collect(Collectors.toList());
            //第一种按照载重来计算
            //过滤载重的错误数据
            List<GantryCraneCaData> gantryCraneCaList = originalGantryCraneCaList.stream().filter(gantryCraneCaData -> {
                if (gantryCraneCaData.getLoadCapacity()
                        .compareTo(new BigDecimal(gantryCraneCaData.getMaxLoadCapacity()).multiply(new BigDecimal("1.5"))) >= 0) {
                    return false;
                }
                return true;
            }).collect(Collectors.toList());
            //移动位 标记位
            int i = 0,k=0;
            int j = i+1;
            BigDecimal preIndex=new BigDecimal("0");
            BigDecimal seqIndex=new BigDecimal("0");
            for (; i <gantryCraneCaList.size()-1 && j<gantryCraneCaList.size(); i++,j++) {
                preIndex = gantryCraneCaList.get(i).getLoadCapacity();
                seqIndex = gantryCraneCaList.get(j).getLoadCapacity();
                //不相等记录之前的实时数据生成任务
                if ((preIndex.compareTo(new BigDecimal("0"))==0 && seqIndex.compareTo(new BigDecimal("0"))>0)
                        ||(preIndex.compareTo(new BigDecimal("0"))>0 && seqIndex.compareTo(new BigDecimal("0"))==0)) {
                    //不相等
                    //构建任务明细
                    List<GantryCraneCaData> gantryCraneCaTask =new ArrayList<>();
                    if (k==i){
                        GantryCraneCaData gantryCraneCaData = gantryCraneCaList.get(k);
                        gantryCraneCaTask.add(gantryCraneCaData);
                    }else {
                        gantryCraneCaTask = gantryCraneCaList.subList(k,j);
                    }
                    gantryCraneCaTaskList.add(gantryCraneCaTask);
                    //计算任务数据
                    //标记参与计算
                    //求和项
                    //处理经纬度数据
                    k=j;
                }
            }
            //遗留数据重新计算
            List<GantryCraneCaData> gantryCraneCaTask = gantryCraneCaList.subList(k,gantryCraneCaList.size());
            gantryCraneCaTaskList.add(gantryCraneCaTask);
        });

        if(CollectionUtil.isNotEmpty(gantryCraneCaTaskList)){
            gantryCraneCaTaskList.stream().forEach(gantryCraneCaDataList->{
                splitData(gantryCraneCaDataList).stream().filter(CollectionUtil::isNotEmpty).forEach(gantryCraneCaData -> {
                    DeviceDataCalcd flatCarDeviceDataCalcds = getGantryCraneCaDeviceDataCalcds(gantryCraneCaData);
                    deviceDataCalcds.add(flatCarDeviceDataCalcds);
                    updateGantryCraneCaDatas.addAll(gantryCraneCaData);
                });
            });
        }
        if (CollectionUtil.isNotEmpty(updateGantryCraneCaDatas)) {
            gantryCraneCaDataService.updateBatchById(updateGantryCraneCaDatas);
        }
        if(CollectionUtil.isNotEmpty(deviceDataCalcds)){
            List<DeviceDataCalcd> insertList = deviceDataCalcds.stream().filter(deviceDataCalcd -> deviceDataCalcd != null).collect(Collectors.toList());
            deviceDataCalcdService.saveBatch(insertList);
        }
    }

    /***
     * 时间跨度超过60分钟做任务分割
     * @param gantryCraneCaDataList
     * @return
     */
    List<List<GantryCraneCaData>> splitData(List<GantryCraneCaData> gantryCraneCaDataList){
        List<List<GantryCraneCaData>> gantryCraneCaTaskList=new ArrayList<>();
        if (gantryCraneCaDataList.size()!=1) {
            //标志位
            int k = 0;
            int i = 0;
            int j=i+1;
            boolean flag = true;
            for (; i <gantryCraneCaDataList.size()-1; i++,j++) {
                long time = gantryCraneCaDataList.get(j).getDataTime().getTime()-gantryCraneCaDataList.get(i).getDataTime().getTime();
                if (new BigDecimal(time).divide(new BigDecimal("1000"), 1, RoundingMode.HALF_UP)
                        .divide(new BigDecimal("60"), 1, RoundingMode.HALF_UP).compareTo(new BigDecimal("60"))>=1) {
                    flag=false;
                    gantryCraneCaTaskList.add(gantryCraneCaDataList.subList(k,j));
                    k=j;
                }

            }
            if (flag){
                //没有发生分割
                gantryCraneCaTaskList.add(gantryCraneCaDataList);
            }else {
                //分割最后数据
                gantryCraneCaTaskList.add(gantryCraneCaDataList.subList(k,j));
            }
        }
        return gantryCraneCaTaskList;
    }


    /**
     * 计算任务数据
     * @param gantryCraneCaTask
     * @return
     */
    public DeviceDataCalcd getGantryCraneCaDeviceDataCalcds(List<GantryCraneCaData> gantryCraneCaTask){
        //不相等
        //构建任务明细
        DeviceDataCalcd deviceDataCalcd = new DeviceDataCalcd();
        //计算任务数据
        //求和项
        //处理经纬度数据
        List<GantryCraneCaData> location = gantryCraneCaTask.stream()
                .filter(gantryCraneCaData -> com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(gantryCraneCaData.getLatitude())
                        && com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(gantryCraneCaData.getLongitude())).collect(Collectors.toList());

        BigDecimal mileage = calculateDistance(null, location);
        //时长
        long l = gantryCraneCaTask.get(gantryCraneCaTask.size()-1).getDataTime().getTime() - gantryCraneCaTask.get(0).getDataTime().getTime();
        BigDecimal loadTimeValue = new BigDecimal(l).divide(new BigDecimal("1000"), 1, RoundingMode.HALF_UP);

        //载重
        BigDecimal loadCapacity = calculateAverage(gantryCraneCaTask.stream().map(GantryCraneCaData::getLoadCapacity).collect(Collectors.toList()));
//                    生成任务明细
        if (loadCapacity.compareTo(new BigDecimal("0"))==1){
            //是否是载重状态
            deviceDataCalcd.setCalcdType(CalcdTypeEnum.LOAD.getValue());
            //判断载重类型
            if (loadCapacity.compareTo(new BigDecimal("30"))==1){
                //大负载
                deviceDataCalcd.setLoadType(LoadTypeEnum.HEAVYLOAD.getValue());
            }else {
                //小负载
                deviceDataCalcd.setLoadType(LoadTypeEnum.SMALLLOAD.getValue());
            }
            //判断任务有效性
            if (loadTimeValue.divide(new BigDecimal("60"), 1, RoundingMode.HALF_UP).compareTo(new BigDecimal("15"))==1){
                //有效任务
                deviceDataCalcd.setLoadValid(LoadValidEnum.VALID.getValue());
            }else if (loadTimeValue.divide(new BigDecimal("60"), 1, RoundingMode.HALF_UP).compareTo(new BigDecimal("15"))<=0){
                //无效任务
                deviceDataCalcd.setLoadValid(LoadValidEnum.INVALID.getValue());
            }
            //设备编号
            deviceDataCalcd.setDeviceNo(gantryCraneCaTask.get(0).getDeviceNo());
            //任务开始时间
            deviceDataCalcd.setStartTime(DateUtil.formatDateTime(gantryCraneCaTask.get(0).getDataTime()));
            deviceDataCalcd.setCreateTime(DateUtil.formatDateTime(gantryCraneCaTask.get(0).getDataTime()));
            //任务结束时间
            deviceDataCalcd.setEndTime(DateUtil.formatDateTime(gantryCraneCaTask.get(gantryCraneCaTask.size()-1).getDataTime()));
            //载重重量
            deviceDataCalcd.setLoadCapacity(loadCapacity);
            //最大载重重量
            BigDecimal maxLoadCapacity = calculateMax(gantryCraneCaTask.stream().map(GantryCraneCaData::getLoadCapacity).collect(Collectors.toList()));
            deviceDataCalcd.setLoadCapacityMax(maxLoadCapacity);
            //平均载重
            deviceDataCalcd.setLoadCapacityAvg(loadCapacity);
            //里程
            //任务所经过的经纬度
            List<String> positions = new ArrayList<>();
            gantryCraneCaTask.stream().forEach(flatCarData->{
                String position=flatCarData.getLongitude()+","+flatCarData.getLatitude();
                positions.add(position);
            });
            deviceDataCalcd.setLatLongList(positions);
            deviceDataCalcd.setMileage(mileage);
            //任务时长 单位:s
            deviceDataCalcd.setLoadTime(loadTimeValue);
            //车速
            //最大车速
            //平均车速
            //任务类型
            deviceDataCalcd.setGantryCraneType(GantryCraneTypeEnum.MAINTASK.getValue());
        }else if (loadCapacity.compareTo(new BigDecimal("0"))==0){
            //是否是载重状态
            deviceDataCalcd.setCalcdType(CalcdTypeEnum.NOLOAD.getValue());
            //设备编号
            deviceDataCalcd.setDeviceNo(gantryCraneCaTask.get(0).getDeviceNo());
            //任务开始时间
            deviceDataCalcd.setStartTime(DateUtil.formatDateTime(gantryCraneCaTask.get(0).getDataTime()));
            deviceDataCalcd.setCreateTime(DateUtil.formatDateTime(gantryCraneCaTask.get(0).getDataTime()));
            //任务结束时间
            deviceDataCalcd.setEndTime(DateUtil.formatDateTime(gantryCraneCaTask.get(gantryCraneCaTask.size()-1).getDataTime()));
            //载重重量
            deviceDataCalcd.setLoadCapacity(loadCapacity);
            //任务所经过的经纬度
            List<String> positions = new ArrayList<>();
            gantryCraneCaTask.stream().forEach(flatCarData->{
                String position=flatCarData.getLongitude()+","+flatCarData.getLatitude();
                positions.add(position);
            });
            deviceDataCalcd.setLatLongList(positions);
            //里程
            deviceDataCalcd.setMileage(mileage);
            //任务时长 单位:s
            deviceDataCalcd.setLoadTime(loadTimeValue);
            //任务类型
            deviceDataCalcd.setGantryCraneType(GantryCraneTypeEnum.MAINTASK.getValue());
        }else {
            return null;
        }
        //绑定原始数据和任务数据关系
        deviceDataCalcd.setCalcdNo(IdUtil.simpleUUID());
        gantryCraneCaTask.stream().forEach(gantryCraneCaData -> {
            gantryCraneCaData.setCalcdNo(deviceDataCalcd.getCalcdNo());
        });
        return deviceDataCalcd;
    }



    //里程
    public static BigDecimal calculateDistance(List<FlatCarData> flatCarDataList, List<GantryCraneCaData> gantryCraneCaDataList) {

        BigDecimal sum = new BigDecimal("0");
        if (CollectionUtil.isNotEmpty(flatCarDataList)){
            for (int i = 0,j=i+1; i <flatCarDataList.size()-1 && j<flatCarDataList.size(); i++,j++) {
                Double lat1 = Double.valueOf(flatCarDataList.get(i).getLatitude());
                Double lat2 = Double.valueOf(flatCarDataList.get(j).getLatitude());
                Double lon1 = Double.valueOf(flatCarDataList.get(i).getLongitude());
                Double lon2 = Double.valueOf(flatCarDataList.get(j).getLongitude());
                sum=sum.add(new BigDecimal(GeoUtils.getDistance(lon1,lat1,lon2,lat2)));
            }
        }

        if (CollectionUtil.isNotEmpty(gantryCraneCaDataList)){
            for (int i = 0,j=i+1; i <gantryCraneCaDataList.size()-1 && j<gantryCraneCaDataList.size(); i++,j++) {
                Double lat1 = Double.valueOf(gantryCraneCaDataList.get(i).getLatitude());
                Double lat2 = Double.valueOf(gantryCraneCaDataList.get(j).getLatitude());
                Double lon1 = Double.valueOf(gantryCraneCaDataList.get(i).getLongitude());
                Double lon2 = Double.valueOf(gantryCraneCaDataList.get(j).getLongitude());
                sum=sum.add(new BigDecimal(GeoUtils.getDistance(lon1,lat1,lon2,lat2)));
            }
        }

        return sum.divide(new BigDecimal("1000"), 6, RoundingMode.HALF_UP);
    }


    public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
//    处理后按点计算
        Point2D pointDD = new Point2D.Double(lon1, lat1);
        Point2D pointXD = new Point2D.Double(lon2, lat2);

        return DistanceUtil.getDistance(pointDD, pointXD);
//    原经纬度数据
    }


    /**
     * 通过经纬度，计算里程数
     *
     //         * @param latLongList 经纬度集合
     * @return 距离（KM）
     */
    private BigDecimal getMileage(String latLongList) {
        BigDecimal mileage = BigDecimal.ZERO;
        if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isEmpty(latLongList)) {
            return mileage;
        }
        String[] latLongStrArr = latLongList.split("\\|");
        for (int i = 0; i < latLongStrArr.length - 1; i++) {

            String startLatLongStr = latLongStrArr[i];
            String endLatLongStr = latLongStrArr[i + 1];

            if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(startLatLongStr) && StringUtils.isNotEmpty(endLatLongStr)
                    && !",".equals(startLatLongStr) && !",".equals(endLatLongStr)) {
                String[] latLongArr1 = startLatLongStr.split(",");
                Point2D pointDD = new Point2D.Double(Double.parseDouble(latLongArr1[0]), Double.parseDouble(latLongArr1[1]));

                String[] latLongArr2 = endLatLongStr.split(",");
                Point2D pointXD = new Point2D.Double(Double.parseDouble(latLongArr2[0]), Double.parseDouble(latLongArr2[1]));

                mileage = mileage.add(BigDecimal.valueOf(DistanceUtil.getDistance(pointDD, pointXD)));
            }
        }
        //M转换成KM
        mileage = mileage.divide(new BigDecimal("1000"), 2, RoundingMode.HALF_UP);
        return mileage;
    }


    //计算平均值
    public static BigDecimal calculateAverage(List<BigDecimal> numbers) {
        BigDecimal divide =new BigDecimal("0");
        if (CollectionUtil.isNotEmpty(numbers)) {
            ArrayList<BigDecimal> list = new ArrayList<>();
            numbers.stream().forEach(number->list.add(number));
            BigDecimal sum = list.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            divide = sum.divide(BigDecimal.valueOf(numbers.size()), 2, BigDecimal.ROUND_HALF_UP);
        }
        return divide;
    }

    //计算最大值
    public static BigDecimal calculateMax(List<BigDecimal> numbers) {
        BigDecimal max = numbers.stream().max((num1, num2) -> num2.compareTo(num1)).get();
        return max;
    }



    public static void main(String[] args) {
                List<Integer> integerList = new ArrayList<>();
                integerList.add(1);
                integerList.add(2);
                integerList.add(3);
                List<Integer> subList = integerList.subList(3, 3);
                System.out.println("originList：" + integerList);
                System.out.println("subList：" + subList);
    }

}
